use std::sync::Arc;

use crate::classfile;

use super::{ConstantPool, class::Class, method::Method, method_lookup};

// 接口方法符号引用
#[derive(Clone)]
pub struct InterfaceMethodRef{
    cp: Arc<ConstantPool>,
    class_name: String, // 类的完全限定名
    class: Option<Arc<Class>>, // 缓存解析后的类结构体
    // cp_symref ↑
    name: String,
    descriptor: String,
    // cp_memberref ↑
    method: Option<Arc<Method>>
}

// cp_symref
impl InterfaceMethodRef {
    // 字段符号引用解析
    pub fn resolved_class(&mut self) -> Arc<Class> {
        if self.class.is_none() {
            self.resolve_class_ref();
        }
        self.class.as_ref().unwrap().clone()
    }

    // 解析class引用
    fn resolve_class_ref(&mut self) {
        let d = self.cp.get_class();
        let loader = d.get_class_loader().unwrap();
        // TODO class_name 用的clone，后续调整标记
        let c = loader.lock().unwrap().load_class(self.class_name.clone());
        if !c.is_accessible_to(d.as_ref()) {
            panic!("java.lang.IllegalAccessError");
        }
        self.class = Some(c);
    }
}

// cp_memberref
impl InterfaceMethodRef {
   // 从class文件内存储的字段或方法常量中提取数据
   pub fn copy_member_ref_info(&mut self, ref_info: &classfile::ConstatnInterfaceMethodrefInfo) {
        self.class_name = ref_info.class_name();
        let (name, deciroptor) = ref_info.name_and_descriptor();
        self.name = name;
        self.descriptor = deciroptor;
    }

    pub fn get_name(&self) -> &str {
        &self.name
    }

    pub fn get_descriptor(&self) -> &str {
        &self.descriptor
    }
}

impl InterfaceMethodRef {
    pub fn new_interface_method_ref(cp: Arc<ConstantPool>, ref_info: &classfile::ConstatnInterfaceMethodrefInfo) -> InterfaceMethodRef {
        let mut im_ref = InterfaceMethodRef { 
            cp, 
            class_name: String::default(), 
            class: None, 
            name: String::default(), 
            descriptor: String::default(), 
            method: None 
        };
        im_ref.copy_member_ref_info(ref_info);
        im_ref
    }

    // 字段符号引用解析
    pub fn resolved_interface_method(&mut self) -> Arc<Method> {
        if self.method.is_none() {
            self.resolved_interface_method_ref()
        }
        self.method.as_ref().unwrap().clone()
    }

    // 解析方法引用
    fn resolved_interface_method_ref(&mut self) {
        let c = self.resolved_class();
        let d = self.cp.get_class();
        if !c.is_interface() {
            panic!("java.lang.IncompatibleClassChangeError")
        }
        match Self::lookup_interface_method(c, &self.name, &self.descriptor) {
            Some(method) if !method.is_accessible_to(d) => panic!("java.lang.IllegalAccessError"), // 无权访问
            Some(method) => self.method = Some(method), // 设置method
            None => panic!("java.lang.NoSuchFieldError")
        }
    }

    // 查找方法
    fn lookup_interface_method(c: Arc<Class>, name: &str, descriptor: &str) -> Option<Arc<Method>> {
        // 在接口方法中查找
        for method in c.get_methods(false) {
            if method.get_name() == name && method.get_descriptor() == descriptor {
                return Some(method);
            }
        }
        // 实现接口中查找
        method_lookup::lookup_method_in_interfaces(c.get_interfaces(), name, descriptor)
    }
}
